<template>
  <div ref="CollapseCompRef" class="CollapseComp">
    <ul>
      <li
        v-for="(item, index) in collapseList"
        :key="index"
        ref="liRefs"
        :style="{
          height: domHeightArr[index] + 'px'
        }"
        :class="{ 'expand': expandIndex.includes(index), 'shrink': !expandIndex.includes(index), [item.slotName]: true }">
        <p class="collTitle" @click="clickItem(index)">
          <span class="title_name">
            <img src="./arrow.svg">
            {{$t(item.title)}}
          </span>
          <span class="slot_name">
            <slot :name="item.slotName + 'Title'"></slot>
          </span>
        </p>
        <div class="content">
          <slot :name="item.slotName"></slot>
        </div>
        <div
          v-if="isShowLine(index)"
          class="bottomLine"
          :class="{ indragging: indragging && currentIndex === index }"
          @mousedown="handleMouseDown($event, index)"></div>
      </li>
    </ul>
  </div>
</template>
<script lang="ts"  setup>
import { ref, computed, onBeforeUnmount, onMounted, Ref, PropType } from "vue";
type CollapseItem = {
  title: string,
  slotName: string
}
const props = defineProps({
  collapseList: {
    type: Array as PropType<CollapseItem[]>,
    default: () => []
  },
  expandAllItem: {
    type: Boolean,
    default: true
  }
});
const liRefs = ref([]) as Ref<HTMLDivElement[]>;
const CollapseCompRef = ref<HTMLDivElement>();
const expandIndex = ref<number[]>([]);
const isShowLine = (index: number) => {
  return expandIndex.value.includes(index) && expandIndex.value[expandIndex.value.length - 1] !== index;
};
const domHeightArr = ref(new Array(props.collapseList.length).fill(30));
const originDomHeight = ref(0);
const mouseStartY = ref(0);
const indragging = ref(false);
const currentIndex = ref(0);
const minHeight = computed(() => {
  return originDomHeight.value / props.collapseList.length - (originDomHeight.value / props.collapseList.length) / 2;
});
const resizeObserver = ref<ResizeObserver>();
onMounted(() => {
  originDomHeight.value = CollapseCompRef.value?.offsetHeight || 500;
  if (props.expandAllItem) {
    domHeightArr.value.forEach((_, i) => {
      domHeightArr.value[i] = originDomHeight.value / props.collapseList.length;
      expandIndex.value.push(i);
    });
  }
  clickItem(3);
  resizeObserver.value = new ResizeObserver(entries => {
    const dom = entries[0];
    const changeHeight = dom.contentRect.height - originDomHeight.value;
    if (expandIndex.value.length > 0){
      domHeightArr.value.forEach((_, i) => {
        if (expandIndex.value.includes(i)) {
          domHeightArr.value[i] += changeHeight / expandIndex.value.length;
        }
      });
    }
    originDomHeight.value = dom.contentRect.height;
  });
  resizeObserver.value.observe(CollapseCompRef.value as HTMLDivElement);

});
onBeforeUnmount(() => {
  resizeObserver.value?.unobserve(CollapseCompRef.value as HTMLDivElement);
});
const clickItem = (index: number) => {
  if (expandIndex.value.includes(index)) {
    expandIndex.value.splice(expandIndex.value.indexOf(index), 1);
    const extraHeight = domHeightArr.value[index] - 30;
    domHeightArr.value.forEach((_, i) => {
      if (expandIndex.value.includes(i)) {
        domHeightArr.value[i] += extraHeight / expandIndex.value.length;
      }
    });
    domHeightArr.value[index] = 30;
  } else {
    expandIndex.value.push(index);
    const averageHeight = originDomHeight.value / expandIndex.value.length;
    if (restHeight.value < averageHeight) {
      let cha = averageHeight - restHeight.value;
      for (let i = 0; i < props.collapseList.length; i++) {
        if (i !== index && domHeightArr.value[i] > averageHeight) {
          let one = domHeightArr.value[i] - averageHeight;
          if (one > cha) {
            domHeightArr.value[i] = domHeightArr.value[i] - cha;
            break;
          } else {
            cha -= one;
            domHeightArr.value[i] = averageHeight;
          }
        }
      }
      domHeightArr.value[index] = averageHeight;
    } else {
      domHeightArr.value[index] = restHeight.value + 30;
    }
  }
};
const restHeight = computed(() => {
  let count = domHeightArr.value.reduce((total, current, index, arr) => {
    return total + current;
  }, 0);
  return originDomHeight.value - count;
});
const handleMouseDown = (event: MouseEvent, index: number) => {
  mouseStartY.value = event.clientY;
  indragging.value = true;
  currentIndex.value = index;
  liRefs.value.forEach(one => {
    one.style.transition = 'none';
  });
  window.addEventListener('mousemove', handleMouseMove);
  window.addEventListener('mouseup', handleMouseUp);
};
const handleMouseUp = () => {
  indragging.value = false;
  liRefs.value.forEach(one => {
    one.style.transition = 'all 0.5s';
  });
  window.removeEventListener('mousemove', handleMouseMove);
  window.removeEventListener('mouseup', handleMouseUp);
};
const testFun = (index: number, absHeight: number) => {
  let count = absHeight;
  const result = {
    isBreak: false,
    absHeight
  };
  if (domHeightArr.value[index] > minHeight.value) {
    const cha = domHeightArr.value[index] - minHeight.value;
    if (cha > count) {
      domHeightArr.value[index] = domHeightArr.value[index] - count;
      count = 0;
      result.isBreak = true;
    } else {
      domHeightArr.value[index] = minHeight.value;
      count -= cha;
    }
    result.absHeight = count;
  }
  return result;
};
const handleMouseMove = (event: any) => {
  const mouseEndY = event.clientY;
  let changeHeight = mouseEndY - mouseStartY.value;
  let absHeight = Math.abs(changeHeight);
  let finallyNum = 0;
  if (changeHeight < 0) {
    for (let i = currentIndex.value; i >= 0; i--) {
      const result = testFun(i, absHeight);
      absHeight = result.absHeight;
      if (!result) {
        break;
      }
    }
    if (absHeight > 0) {
      finallyNum = Math.abs(changeHeight) - absHeight;
    } else {
      finallyNum = Math.abs(changeHeight);
    }
    for (let i = currentIndex.value + 1; i <= props.collapseList.length; i++) {
      if (expandIndex.value.includes(i)) {
        domHeightArr.value[i] = domHeightArr.value[i] + finallyNum;
        break;
      }
    }
  } else {
    if (restHeight.value > absHeight) {
      finallyNum = absHeight;
    } else {
      for (let i = currentIndex.value + 1; i < props.collapseList.length; i++) {
        const result = testFun(i, absHeight);
        absHeight = result.absHeight;
        if (!result) {
          break;
        }
      }
      if (absHeight > 0) {
        finallyNum = Math.abs(changeHeight) - absHeight;
      } else {
        finallyNum = Math.abs(changeHeight);
      }
    }
    domHeightArr.value[currentIndex.value] = domHeightArr.value[currentIndex.value] + finallyNum;
  }
  mouseStartY.value = event.clientY;
};
</script>
<style lang="scss">
.CollapseComp {
  height: 100%;
  ul {
    display: flex;
    flex-direction: column;
    height: 100%;

    li {
      width: 100%;
      overflow: hidden;
      position: relative;
      transition: all 0.5s;
      border-bottom: 1px solid #E4E4E4;

      .collTitle {
        cursor: pointer;
        background-color: #ECF4FF;
        color: black;
        width: 100%;
        height: 30px;
        display: flex;
        align-items: center;

        .title_name {
          display: inline-block;
          padding-left: 5px;
          width: 300px;

          >img {
            width: 15px;
            height: 15px;
            transition: all 0.5s;
            margin-top: -3px;
          }
        }

        .slot_name {
          width: calc(100% - 60px);
        }
      }

      .content {
        overflow-y: auto;

      }

      .bottomLine {
        position: absolute;
        bottom: 0;
        height: 4px;
        opacity: 0;
        width: 100%;
        &:hover {
          opacity: 1;
          cursor: n-resize;
        }
      }

      .indragging {
        background-color: #A2B3CD;
        opacity: 1;
      }
    }

    li:first-child {
      border-top: 1px solid #E4E4E4;
    }

    .expand {
      .content {
        height: calc(100% - 30px - 0px);
      }

      .collTitle {
        .title_name {
          img {
            transform: rotate(90deg);
          }
        }

      }
    }

    .shrink {
      height: 30px;

      .content {
        height: 0;
      }
    }
  }
}
</style>
